`timescale 1 ns / 1 ps
`default_nettype none

/***********************************************************************
This file is part of the ChipWhisperer Project. See www.newae.com for more
details, or the codebase at http://www.chipwhisperer.com

Copyright (c) 2023, NewAE Technology Inc. All rights reserved.
Author: Jean-Pierre Thibault <jpthibault@newae.com>

  chipwhisperer is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  chipwhisperer is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with chipwhisperer.  If not, see <http://www.gnu.org/licenses/>.
*************************************************************************/

module ss_aes_top (
    output wire         CLKOUT,
    input  wire         CLKIN,

    output wire         IO1,
    input  wire         IO2,
    input  wire         IO3,
    output wire         IO4,

    output wire [3:1]   LED,
    inout  wire [10:1]  HDR,

    input  wire         nRST,
    input  wire         SCK,
    output wire         MISO,
    input  wire         MOSI,

    output wire         nRST_OUT,

    output wire         TRACECLK,
    output wire [3:0]   TRACEDATA
);

    assign CLKOUT = 1'bz;
    assign MISO = 1'b0;
    assign HDR = 10'bZ;
    assign LED[3] = clkout_hearbeat[22];
    assign TRACECLK = 1'bz;
    assign TRACEDATA = 4'bz;
    assign nRST_OUT = 1'bz;

    wire [127:0] enc_input;
    wire [127:0] enc_output [0:`AES_INSTANCES];
    wire [127:0] enc_key;
    wire load_input;                    //One-clock cycle flag to indicate data in enc_input is valid
    wire load_key;                      //One-cycle flag to indicate data in enc_input is valid
    wire enc_go_master;                 //One-cycle flag to indicate we should run an encryption
    wire enc_go [0:`AES_INSTANCES];
    wire enc_output_ready;              //One-cycle flag generated by encryption core indicating data out is valid
    wire [9:0] aes_select = HDR;        //pull downs on HDR to default to 0
    reg [24:0] clkout_hearbeat = 0;

    wire clk;
    `ifdef __ICARUS__
        assign clk = CLKIN;
    `else
        IBUFG IBUFG_usb_inst (
            .O(clk),
            .I(CLKIN)
        );
    `endif

    always @(posedge clk) clkout_hearbeat <= clkout_hearbeat +  25'd1;

    SimpleSerial SSCore(
        .clk            (clk), 
        .TxD            (IO1), 
        .RxD            (IO2), 
        .LED_rx         (LED[1]), 
        .LED_go         (LED[2]),
        .pt             (enc_input), 
        .key            (enc_key), 
        .load_key       (load_key), 
        .load_pt        (load_input),
        .do_enc         (enc_go_master), 
        .ct             (enc_output[aes_select]), 
        .ct_ready       (enc_output_ready)
    );

    wire enc_busy[0:`AES_INSTANCES];
    assign IO4 = enc_busy[0];

    // Multiple identical AES modules are instantiated as per the AES_INSTANCE
    // define. The input data to each module is 1 + the input data to the
    // previous module. The HDR lines allow to select which module's output
    // gets read out (this is mostly to prevent synthesis from optimizing away
    // the multiple modules for redundancy). Finally, IO3 controls whether
    // only one module is active, or all of them.
    genvar i;
    generate 
        for (i = 0; i < `AES_INSTANCES; i = i + 1) begin: gen_aes_instances
            assign enc_go[i] = (i == 0)? enc_go_master : (enc_go_master && IO3);
            aes_core AESGoogleVault(
                .clk            (clk),
                .load_i         (enc_go[i]),
                .key_i          ({enc_key, 128'h0}),
                .data_i         (enc_input+i),
                .size_i         (2'd0),
                .dec_i          (1'b0),
                .data_o         (enc_output[i]),
                .busy_o         (enc_busy[i])
            );
        end
    endgenerate

    //Generate single-clock cycle pulse when enc_busy falls
    reg enc_done_flag;
    reg enc_busy_delayed;
    always @(posedge clk) enc_busy_delayed <= enc_busy[0];
    always @(posedge clk) enc_done_flag <= ~enc_busy[0] & enc_busy_delayed;
    assign enc_output_ready = enc_done_flag;

endmodule
`default_nettype wire
